﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;

namespace NFinalControllerGenerator
{
    public class StructModel
    {
        public byte[] GetDocument(StringWriter sw, Document document,CSharpCompilation cSharpCompilation)
        {
            SyntaxTree tree = null;
            if (document != null)
            {
                tree = document.GetSyntaxTreeAsync().Result;
                SyntaxNode root = tree.GetRoot();
                SemanticModel model = cSharpCompilation.GetSemanticModel(tree);
                var controllers = root.DescendantNodes().OfType<ClassDeclarationSyntax>();

                if (controllers.Count() > 0)
                {
                    var controller = controllers.First();
                    var controllerSymbol = model.GetDeclaredSymbol(controller);
                    Dictionary<string, DeclareData> filesAndPropertys = new Dictionary<string, DeclareData>();
                    int level = 0;
                    GetFieldsUtility.GetAllFieldsAndPropertys(controllerSymbol, level, ref filesAndPropertys);
                    var rootUnit = (CompilationUnitSyntax)root;
                    foreach (var us in rootUnit.Usings)
                    {
                        sw.Write(us.ToFullString());
                    }
                    sw.WriteLine("//此代码由NFinalControllerGenerator生成。");
                    sw.WriteLine("//http://bbs.nfinal.com");
                    sw.Write("namespace ");
                    sw.Write(controllerSymbol.ContainingNamespace.ToString());
                    sw.Write(".");
                    sw.Write(controllerSymbol.Name);
                    sw.WriteLine("_Model");
                    sw.WriteLine("{");

                    var actions = root.DescendantNodes().OfType<MethodDeclarationSyntax>();
                    string viewBagTypeName = null;
                    string structName = null;
                    foreach (var action in actions)
                    {
                        Dictionary<string, DeclareData> methodFields = new Dictionary<string, DeclareData>();
                        Dictionary<string, DeclareData> ViewBagFields = new Dictionary<string, DeclareData>();
                        foreach (var fap in filesAndPropertys)
                        {
                            ViewBagFields.Add(fap.Key, fap.Value);
                        }
                        var attributeList = action.ChildNodes().OfType<AttributeListSyntax>();
                        var actionSymbol = model.GetDeclaredSymbol(action);
                        structName = actionSymbol.Name;
                        foreach (var attrList in attributeList)
                        {
                            foreach (var attr in attrList.Attributes)
                            {
                                if (attr.Name.ToString() == "HttpPost")
                                {
                                    structName = structName + "HttpPost";
                                    break;
                                }
                                else if (attr.Name.ToString() == "HttpGet")
                                {
                                    structName = structName + "HttpGet";
                                    break;
                                }
                            }
                        }

                        GetFieldsUtility.GetLocalVars(action, model, ref methodFields);
                        foreach (var methodField in methodFields)
                        {
                            if (!ViewBagFields.ContainsKey(methodField.Key))
                            {
                                ViewBagFields.Add(methodField.Key, methodField.Value);
                            }
                        }
                        viewBagTypeName =
                            controllerSymbol.Name + "_Model." + actionSymbol.Name;
                        var ViewBagFieldList = ViewBagFields.ToList();
                        for (int i = ViewBagFieldList.Count - 1; i >= 0; i--)
                        {
                            if (ViewBagFieldList[i].Value.Type.Contains(viewBagTypeName))
                            {
                                ViewBagFieldList.RemoveAt(i);
                            }
                        }
                        sw.Write("\tpublic struct ");
                        sw.WriteLine(structName);
                        sw.WriteLine("\t{");
                        GetFieldsUtility.BuildStruct(sw, ViewBagFieldList);
                        sw.WriteLine("\t}");
                    }
                    sw.WriteLine("}");
                }
            }
            return System.Text.Encoding.UTF8.GetBytes(sw.ToString());
        }
    }
}